/*
 * Board.cpp
 *
 *  Created on: Apr 1, 2014
 *      Author: zby
 */
#include "Board.h"

using namespace board;
//--------------------------------------------------------------------------------
//means nodes're connected but init value to create hex board
graph::EdgeVal const Board::EdgeInit = 0xFF;
//means nodes're connected (two moves sticky) for player A
graph::EdgeVal const Board::EdgeConPlayer_A = 0xAA;
//means nodes're connected (two moves sticky) for player B
graph::EdgeVal const Board::EdgeConPlayer_B = 0xBB;
//--------------------------------------------------------------------------------

/*
* @brief    Constructor for board. Connecting node to HEX-board representation.
*             Board is square of size x size. All node value are vacant (set to NONE).
*
* @param    size of board max 100.
* @retval    none
*/
Board::Board(unsigned int _size) : graph::Graph( (graph::Node) _size*_size ), size(_size),fau_WE(_size*_size), fau_SN(_size*_size){

    if (_size>100) throw "size exceed - max 100";

    //make connection to produce HEX board _size x _size
    //using namespace graph;
    for(graph::Node i=0; i<size; i++)
        for(graph::Node j=0; j<size; j++)
        {
            //--------corners--------------------
            if(i==0 && j==0)
            {
                AddEdge(_size*i+j,1,Board::EdgeInit);
                AddEdge(_size*i+j,_size,Board::EdgeInit);
            }
            else if(i==0 && j==(_size-1))
            {
                AddEdge(_size*i+j,j-1,Board::EdgeInit);
                AddEdge(_size*i+j,j+_size-1,Board::EdgeInit);
                AddEdge(_size*i+j,j+_size,Board::EdgeInit);
            }
            else if(i==(_size-1) && j==0)
            {
                AddEdge(_size*i+j,i*_size+1,Board::EdgeInit);
                AddEdge(_size*i+j,(i-1)*_size,Board::EdgeInit);
                AddEdge(_size*i+j,1+(i-1)*_size,Board::EdgeInit);
            }
            else if(i==(_size-1) && j==(_size-1))
            {
                AddEdge(_size*i+j,i*_size+j-1,Board::EdgeInit);
                AddEdge(_size*i+j,(i-1)*_size+j,Board::EdgeInit);
            }
            //--------north--------------------
            else if(i==0)
            {
                AddEdge(_size*i+j,j-1, Board::EdgeInit);
                AddEdge(_size*i+j,j+1, Board::EdgeInit);
                AddEdge(_size*i+j,j+_size-1, Board::EdgeInit);
                AddEdge(_size*i+j,j+_size, Board::EdgeInit);
            }
            //--------south--------------------
            else if(i==(_size-1))
            {
                AddEdge(_size*i+j,_size*i+j-1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*i+j+1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i-1)+j, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i-1)+j+1, Board::EdgeInit);
            }
            //--------west--------------------
            else if(j==0)
            {
                AddEdge(_size*i+j,_size*(i-1), Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i-1)+1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*i+1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i+1), Board::EdgeInit);
            }
            //--------east--------------------
            else if(j==(_size-1))
            {
                AddEdge(_size*i+j,_size*(i-1)+j, Board::EdgeInit);
                AddEdge(_size*i+j,_size*i+j-1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i+1)+j-1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i+1)+j, Board::EdgeInit);
            }
            //--------rest--------------------
            else
            {
                AddEdge(_size*i+j,_size*i+j-1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*i+j+1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i-1)+j, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i-1)+j+1, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i+1)+j, Board::EdgeInit);
                AddEdge(_size*i+j,_size*(i+1)+j-1, Board::EdgeInit);
            }
            Set_node_value(size*i+j,NONE);
        }

    //Due to West, East, North, South edge can be treated as respective 'line edge',
    //its sensible to connect specified node to create grouped nodes to form West, East, North, South line
    //at the beginning
    for(unsigned i=0; i<_size*_size; i++){
        if(i<_size) fau_SN.unite(i,0);
        else if(i>=_size*(_size-1)) fau_SN.unite(i,_size*_size-1);
        if(!(i%_size)) fau_WE.unite(i,0);
        else if(!((i+1)%_size)) fau_WE.unite(i,_size*_size-1);
    }
}

/*
* @brief    Copy constructor for board.
* @param    board to be copy
* @retval    none
*/
Board::Board(const Board &_b) : graph::Graph(_b), size(_b.size), fau_WE(_b.fau_WE), fau_SN(_b.fau_SN) {

}

/*
* @brief Board Destructor
* @param none
* @retval none
*/
Board::~Board()
{}

/*
* @brief Return board size
* @param none
* @retval Board size
*/
unsigned int Board::GetBoardSize(void)
{
    return this->size;
}

/*
* @brief    Take a move and put them to board if given position is vacancy.
*             This implementation of put_move() base on find & union algorithm.
*             Current move (x,y) will be the root of its neighbors.
* @param    coordinate x
* @param    coordinate y
* @param    players' color (PLAYER_A or PLAYER_B )
* @retval    true if move is legal
*/
bool Board::put_move(pos_X x, pos_Y y, _eplayer eplayer)
{
    // argument validation.
    if(x >= static_cast<pos_X>(size) || y >= static_cast<pos_X>(size)) return false;
    // vacancy
    if(NONE != Get_node_value(static_cast<graph::NodeVal>(x*size+y))) return false;
    // put players' move to (x,y)
    Set_node_value(static_cast<graph::Node>(x*size+y), static_cast<graph::NodeVal> (eplayer));

    // get neighbors of (x,y) node
    std::vector<graph::Node> vNeigh= Neighbors(static_cast<graph::Node>(x*size+y));
    for(std::vector<graph::Node>::iterator it=vNeigh.begin(); it!=vNeigh.end(); it++){
        //if neighbor has the same player sign (PLAYER_A for eplayer == PLAYER_A  or PLAYER_B for eplayer == PLAYER_B)
        //make current move as root of group
        if( (PLAYER_A==eplayer) && (PLAYER_A==static_cast<_eplayer>(Get_node_value(*it))) ){
            this->fau_WE.unite(*it,static_cast<int>(x*size+y));
        }
        else if( (PLAYER_B==eplayer) && (PLAYER_B==static_cast<_eplayer>(Get_node_value(*it))) ){
            this->fau_SN.unite(*it,static_cast<int>(x*size+y));
        }
    }
    return true;
}


